#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include "pac_drawer2D.h"
#include "lc_array.h"
#include "pac_level.h"
#include "pac_object.h"
#include "pac_logger.h"
#include "pac_ghost.h"


void load2DTextures(void) {
    pac_log(LOG_DEBUG, "load2DTextures\n");

    // Données des textures
    GLubyte* texData;

   // Tailles des textures
    int texWidth, texHeight;
    
    // Création du tableau de textures
    glGenTextures(TEX_2D_COUNT, tex2DTable);
    
    // Chargement de la texture de vie de pacman
    texData = glmReadPPM("Textures/pacLife.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex2DTable[PAC_LIFE_TEX]);
    initPacTexture(texData, texWidth, texHeight);
    
    // Chargement de la texture de menu 'Start'
    texData = glmReadPPM("Textures/startMenu.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex2DTable[MAIN_MENU_TEX]);
    initPacTexture(texData, texWidth, texHeight);
     
        // Chargement de la texture de menu 'Pause'
    texData = glmReadPPM("Textures/pauseMenu.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex2DTable[PAUSE_MENU_TEX]);
    initPacTexture(texData, texWidth, texHeight);
    
        // Chargement de la texture de menu 'WIN'
    texData = glmReadPPM("Textures/gameWinMenu.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex2DTable[WIN_MENU_TEX]);
    initPacTexture(texData, texWidth, texHeight);
    
        // Chargement de la texture de menu 'Game Over'
    texData = glmReadPPM("Textures/gameOverMenu.ppm", &texWidth, &texHeight);
    glBindTexture(GL_TEXTURE_2D, tex2DTable[GAMEOVER_MENU_TEX]);
    initPacTexture(texData, texWidth, texHeight);
}

void drawFullScreenTex(int aTex) {

    glPushMatrix();
    glTranslatef(0,0,0);

    glBindTexture(GL_TEXTURE_2D, tex2DTable[aTex]);
    glBegin(GL_QUADS);
    glTexCoord2f(0, 0);
    glVertex2f(0, 1 );
    
    glTexCoord2f(1, 0);
    glVertex2f(1, 1);
    
    glTexCoord2f(1, 1);
    glVertex2f(1, 0);
    
    glTexCoord2f(0, 1);
    glVertex2f(0, 0);
    glEnd();

    glPopMatrix();
}



void draw2DSquare(float posX, float posY) {
   glPushMatrix();
    glTranslatef(posX, posY, 0);
    
    glBegin(GL_QUADS);
    glVertex2f(0, 0);
    glVertex2f(0, 1);
    glVertex2f(1, 1);
    glVertex2f(1, 0);
    glEnd();
    
    glPopMatrix();
       
}

void draw2DRoof(int posX, int posY) {
    glColor3f(0.0, 0.0, 0.6);
    draw2DSquare(posX, posY);
}

void draw2DFloor(int posX, int posY) {
    glColor3f(0.5, 0.5, 0.5);
    draw2DSquare(posX, posY);
}

void draw2DFence(int posX, int posY) {
    glColor3f(0.5, 0.0, 0.5);
    draw2DSquare(posX, posY);
}

void draw2DVortex(int posX, int posY) {
    glColor3f(0.0, 0.5, 1.0);
    draw2DSquare(posX, posY);
}

void draw2DPacManAt(float posX, float posY) {
    glColor3f(1.0, 1.0, 0.0);
    draw2DSquare(posX, posY);
}

void draw2DPacMan(PacObject* aPacMan) {
    pac_log(LOG_DEBUG, "draw2DPacMan\n");
    draw2DPacManAt(aPacMan->posX, aPacMan->posY);
}

void draw2DPacGum(int posX, int posY) {
    glColor3f(0, 0.5, 0.0);
    draw2DSquare(posX, posY);
}

void draw2DPowerBall(int posX, int posY) {
    glColor3f(0, 1, 0.0);
    draw2DSquare(posX, posY);
}

void draw2DPacBall(PacLevel* aLevel, int posX, int posY) {
    // Récupération de la PacGum à la position voulue
    int pacBallCode = levelGetPacBallAt(aLevel, posX, posY);

    switch (pacBallCode) {
        case PAC_GUM_CODE:
            draw2DPacGum(posX, posY);
            break;

        case POWER_BALL_CODE:
            draw2DPowerBall(posX, posY);
            break;

        default:
            // Do nothing
            break;
    }

}

void draw2DGhost(PacGhost * aPacGhost) {
    // Si le fantôme est vulnérable
    if (aPacGhost->isVulnerable) {
        // Il est bleu
        glColor3f(0.4, 0.2, 0.8);
    }// Sinon, s'il retourne à la maison
    else if (aPacGhost->isGoingToHome) {
        // Il est blanc
        glColor3f(0.9, 0.9, 0.9);
    } else {
                // Sinon, Si le fantome est intelligent
        if (aPacGhost->isIntelligent) {
            // Il est en rouge foncé
            glColor3f(0.8, 0.0, 0.0);
        } else {
            // Sinon, il est rouge
            glColor3f(0.4, 0.1, 0.1);
        }
    }

    draw2DSquare(aPacGhost->pacObject->posX, aPacGhost->pacObject->posY);
}

void draw2DGhosts(PacLevel* aLevel) {
    pac_log(LOG_DEBUG, "draw2DGhosts\n");
    int size = lcArrayLength(aLevel->ghosts);

    PacGhost* currentGhost;
    int x;
    for (x = 0; x < size; x++) {
        // Récupération de la ligne courante
        currentGhost = lcArrayGet(aLevel->ghosts, x);
        draw2DGhost(currentGhost);
    }
}

void draw2DCase(PacLevel* aLevel, int aCaseCode, int posX, int posY) {
    switch (aCaseCode) {
        case BLOCK_CODE:
            // Dessin d'un mur
            draw2DRoof(posX, posY);
            break;

        case FENCE_CODE:
            // Dessin d'une barriere
            draw2DFence(posX, posY);
            break;

        default:

            // Si le nombre est négatif
            if (aCaseCode < 0) {
                // Dessin d'un vortex
                draw2DVortex(posX, posY);
            } else {
                // Dessin d'une eventuelle PacBall
                draw2DPacBall(aLevel, posX, posY);

                // Dessin du sol
                draw2DFloor(posX, posY);
            }
            break;
    }
}

void draw2DCases(PacLevel* aLevel) {
    pac_log(LOG_DEBUG, "draw2DCases\n");
    int x, y = 0;
    int sizeY = levelGetSizeY(aLevel);
    int sizeX = levelGetSizeX(aLevel);

    int currentCase;

    for (y = 0; y < sizeY; y++) {
        for (x = 0; x < sizeX; x++) {
            // Récupération de la case courante
            currentCase = levelGetCaseAt(aLevel, x, y);

            //Affichage de la case courante
            draw2DCase(aLevel, currentCase, x, y);
        }
    }
}

void draw2DMap(PacLevel* aLevel) {

    pac_log(LOG_DEBUG, "draw2DMap\n");
    
    glPushMatrix();
    
    // Désactivation des textures
    glBindTexture(GL_TEXTURE_2D, 0);
    
    // Récupération de la taille de la map.
    int sizeY = levelGetSizeY(aLevel);
    int sizeX = levelGetSizeX(aLevel);

    // Récupération de la plus grande taille
    int maxSize = getMaxInt(sizeX, sizeY);

    // Calcul du ratio pour l'affichage
    float sizeDelta = 0.3 / maxSize;
    
            // Déplacement en haut a droite
    glTranslatef(1,1,0);
    
    
    // Modification de l'échelle
    glScalef(sizeDelta, sizeDelta, sizeDelta);
    
    
    // Déplacement pour afficher la map en haut a droite
    glTranslatef(-sizeX,-sizeY,0);
    
    
 

    // Dessin de PacMan
    draw2DPacMan(aLevel->pacMan);

    // Affichage des Fantomes
    draw2DGhosts(aLevel);

    // Affichage du fond de la map
    draw2DCases(aLevel);
    
   glPopMatrix();
}